#include "AppManager.h"
#include "at24cxx.h"

static const uint8_t eeprom_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x07,
   0x10, 0x00, 0x00, 0x04, 0x1e, 0x80, 0x8d, 0x3c, 0x1e, 0x80, 0x54, 0x3d,
   0x10, 0x00, 0xd5, 0x05, 0x1e, 0x80, 0x4d, 0x3d, 0x1e, 0x00, 0x00, 0x3c,
   0x10, 0x80, 0x59, 0x05, 0x1e, 0x80, 0xc4, 0x3c, 0x1e, 0x00, 0x45, 0x3d,
   0x10, 0x80, 0x59, 0x05, 0x1e, 0x00, 0x00, 0x3c, 0x1e, 0x00, 0x00, 0x3c,
   0x10, 0x00, 0x00, 0x04, 0xf0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
   0x30, 0x21, 0x22, 0x00, 0x40, 0x55, 0x55, 0x00, 0x20, 0x17, 0x75, 0x00,
   0x10, 0x54, 0x55, 0x00, 0x70, 0x24, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x70, 0x37, 0x03, 0x00, 0x10, 0x51, 0x25, 0x00,
   0x70, 0x37, 0x53, 0x0a, 0x10, 0x11, 0x55, 0x15, 0x70, 0x17, 0x25, 0x15,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static const menu_item menu_eeprom[] =
    {
        {NULL,"退出"},
        {NULL,"读1Byte"},
        {NULL,"写1Byte"},
        {NULL,"连续读"},
        {NULL,"连续写"},
        {NULL,"填充指定数据"},
        {NULL,"将数据读取到文件"},
        {NULL,NULL},
};

class App24c08 : public AppBase
{
private:
    /* data */
    String toApp = "";
    bool hasToApp = false;
public:
    App24c08()
    {
        name = "24c08";
        title = "eeprom";
        description = "数据读写入";
        image = eeprom_bits;
        _showInList = true;
        noDefaultEvent = true;
    }
    void setup();
    void menu();
    void readByte();
    void writeByte();
    void read();
    void write();
    const char* combineFilePath(const char* path, const char* filename, const char* extension);
    void readtofile();
    void erase();
    int decToBin(int a);
    int binToDec(int binary);
    int mergeints(int num1,int num2);
    void uint8tobuf(uint8_t *input,int inputSize,char *output);
    int lasttowbits(int num);
};
static App24c08 app;

void App24c08::setup()
{
    at24cxx_init();
    GUI::drawWindowsWithTitle("EEPROM读写", 0, 0, 200, 200);
    menu();
}

void App24c08::menu()
{
    display.clearScreen();
    int res = 0;
    bool end = false;
    while(end == false && hasToApp == false)
    {
        display.display(false);
        GUI::drawWindowsWithTitle("EEPROM读写", 0, 0, 200, 200);
        res = GUI::menu("菜单",menu_eeprom);
        switch(res)
        {
            case 0:
                end = true;
                break;
            case 1:
                readByte();
                break;
            case 2:
                writeByte();
                break;
            case 3:
                read();
                break;
            case 4:
                write();
                break;
            case 5:
                erase();
                break;
            case 6:
                readtofile();
                break;
            default:
                break;
        }
    }
    if (hasToApp == true)
    {
        hasToApp = false;
        if (toApp != "")
        {
            appManager.gotoApp(toApp.c_str());
        }
        return;
    }
    appManager.goBack();    
}

void App24c08::readByte()
{
    Serial.printf("[readByte]begin\n");
    char buf[40];
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int addrdate = binToDec(daddrdate);
    int date = at24cxx_read_byte(addrd,addrdate);
    sprintf(buf,"在地址0x%03x\n数据0x%02x",binToDec(mergeints(ladd,daddrdate)),date);
    GUI::msgbox("返回数据",buf);
    Serial.printf("[readByte]end\n");
}

void App24c08::writeByte()
{
    Serial.printf("[writeByte]begin\n");
    char buf[50];
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int addrdate = binToDec(daddrdate);
    int add = at24cxx_read_byte(addrd,addrdate);
    int dat0 = decToBin(add);
    int date = binToDec(GUI::msgbox_number("修改数据",8,dat0));
    at24cxx_write_byte(addrd,addrdate,date);
    int rdate = at24cxx_read_byte(addrd,addrdate);
    sprintf(buf,"在地址0x%03x\n从0x%02x\n修改为0x%02x\n读取为0x%02x",binToDec(mergeints(ladd,daddrdate)),add,date,rdate);
    GUI::msgbox("提示",buf);
    Serial.printf("[writeByte]end\n");
}
void App24c08::read()
{
    Serial.printf("[read]begin\n");
    char buf[1050];
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int addrdate = binToDec(daddrdate);
    int byte = GUI::msgbox_number("输入字节数",4,0000);
    uint8_t bufd[byte];
    at24cxx_read(addrd,addrdate,bufd,byte);
    int s = sizeof(bufd) / sizeof(bufd[0]);
    char result[s * 3 + 1];
    uint8tobuf(bufd,s,result);
    sprintf(buf,"在地址0x%03x\n读数据:%s",binToDec(mergeints(ladd,daddrdate)),result);
    GUI::msgbox("提示",buf);
    Serial.printf("[read]end\n");
}

void App24c08::write()
{
    Serial.printf("[write]begin\n");
    char buf[1050];
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int byte = GUI::msgbox_number("输入字节数",4,0000);
    uint8_t ibuf[byte];
    uint8_t obuf[byte];
    for(int i = 1;i < byte+1;i++)
    {
        ibuf[i] = binToDec(GUI::msgbox_number("输入数据",8,00000000));
    }
    int addrdate = binToDec(daddrdate);
    at24cxx_write(addrd,addrdate,ibuf,byte);
    at24cxx_read(addrd,addrdate,obuf,byte);
    int s = sizeof(obuf) / sizeof(obuf[0]);
    char result[s * 3 + 1];
    uint8tobuf(obuf,s,result);
    sprintf(buf,"在地址0x%03x\n写入数据:%s",binToDec(mergeints(ladd,daddrdate)),result);
    GUI::msgbox("提示",buf);  
    Serial.printf("[write]end\n");
}

void App24c08::readtofile()
{
    Serial.printf("[readtofile]begin\n");
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int addrdate = binToDec(daddrdate);
    int byte = GUI::msgbox_number("输入字节数",4,0000);
    uint8_t bufd[byte];
    at24cxx_read(addrd,addrdate,bufd,byte);
    if(LittleFS.exists("/EEPROM") == false){LittleFS.mkdir("/EEPROM");}
    char buf [10];
    sprintf(buf,"0x%02x",addrd);
    const char *str = buf;
    File f = LittleFS.open(combineFilePath("/EEPROM", str, "bin"),"w");
    f.write(bufd,sizeof(bufd));
    f.close();
    Serial.printf("[readtofile]end\n");
}

void App24c08::erase()
{
    Serial.printf("[erase]begin\n");
    char buf[1050];
    int addr = GUI::msgbox_number("输入器件地址",8,1010000);
    int ladd = lasttowbits(addr);
    int addrd = binToDec(addr);
    int daddrdate = GUI::msgbox_number("输入地址",8,00000000);
    int byte = GUI::msgbox_number("输入字节数",4,0000);
    uint8_t ibuf[byte];
    uint8_t obuf[byte];
    int bufa = binToDec(GUI::msgbox_number("输入数据",8,00000000));
    for(int i = 1;i < byte+1;i++)
    {
        ibuf[i] = bufa;
    }
    int addrdate = binToDec(daddrdate);
    at24cxx_write(addrd,addrdate,ibuf,byte);
    at24cxx_read(addrd,addrdate,obuf,byte);
    int s = sizeof(obuf) / sizeof(obuf[0]);
    char result[s * 3 + 1];
    uint8tobuf(obuf,s,result);
    sprintf(buf,"在地址0x%03x\n写入数据:%s",binToDec(mergeints(ladd,daddrdate)),result);
    GUI::msgbox("提示",buf);
    Serial.printf("[erase]end\n");
}

// 将十进制数转换为二进制字符串
int App24c08::decToBin(int n) {
    int binary = 0;
    int base = 1;

    // 将十进制数转换为二进制数
    while (n > 0) {
        int remainder = n % 2;
        binary += remainder * base;
        n /= 2;
        base *= 10;
    }

    return binary;
}
// 将二进制数转换为十进制数
int App24c08::binToDec(int binary) {
    int decimal = 0;
    int base = 1; // 用于计算每一位的权重
    // 从右到左遍历二进制数，计算十进制数
    while (binary > 0) {
        int digit = binary % 10; // 获取二进制数的最低位
        decimal += digit * base;
        binary /= 10; // 去掉二进制数的最低位
        base *= 2; // 更新权重
    }
    return decimal;
}
int App24c08::mergeints(int num1,int num2)
{
    // 获取num1和num2的位数
    int bits_in_num1 = sizeof(num1) * 8;
    int bits_in_num2 = sizeof(num2) * 8;
    // 计算左移的位数，取两者中较大的位数作为左移的位数
    int shift_count = (bits_in_num1 > bits_in_num2) ? bits_in_num1 : bits_in_num2;
    // 进行左移和按位或操作
    return (static_cast<unsigned int>(num1) << shift_count) | static_cast<unsigned int>(num2);
}
void App24c08::uint8tobuf(uint8_t *input,int inputSize,char *output)
{
    for(int i = 0;i < inputSize;i++)
    {
        sprintf(output + (i * 3),"%02x ",input[i]);
    }
}
int App24c08::lasttowbits(int num)
{
    int mask = 0b11;
    int result = num & mask;
    return result;
}

const char* App24c08::combineFilePath(const char* path, const char* filename, const char* extension) {
    static char result[256]; // 假设路径不超过 256 个字符
    strcpy(result, path); // 复制路径到结果字符串
    strcat(result, "/"); // 添加路径分隔符
    strcat(result, filename); // 添加文件名
    strcat(result, "."); // 添加扩展名的点号
    strcat(result, extension); // 添加扩展名
    return result;
}